package com.learn.util.prop;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 功能：PropKit 能从 classpath 或文件对象中，读取配置
 * <p>相比 Prop，PropKit 添加了配置文件缓存，防止重复加载，提高性能</p>
 *
 * @author wsh
 * @date 2021/1/25
 */
public class PropKit {
    /**
     * 配置文件属性集
     */
    private static Prop prop = null;
    /**
     * 配置文件缓存
     */
    private static final Map<String, Prop> map = new ConcurrentHashMap<String, Prop>();
    /**
     * 配置文件读取编码
     */
    public static String DEFAULT_ENCODING = "UTF-8";

    private PropKit() {
    }

    /**
     * 功能：加载配置文件
     * <p>若未加载将加载，若有加载过直接返回</p>
     *
     * @param fileName 配置文件
     * @return
     * @author wsh
     * @date 2021/1/25
     * @see #use(String, String)
     */
    public static Prop use(String fileName) {
        return use(fileName, DEFAULT_ENCODING);
    }

    /**
     * 功能：加载配置文件
     * <p>
     * 若未加载将加载，若有加载过直接返回<br>
     * 例如：<br>
     * Prop prop = PropKit.use("config.txt", "UTF-8");<br>
     * String userName = prop.get("userName");<br><br>
     * prop = PropKit.use("com/final/config_in_sub_directory_of_classpath.txt");
     * </p>
     *
     * @param fileName 配置文件名称、配置文件对象 ...
     * @param encoding 配置文件读取编码
     * @return
     * @author wsh
     * @date 2021/1/25
     */
    public static Prop use(String fileName, String encoding) {
        Prop result = map.get(fileName);
        if (result == null) {
            result = new Prop(fileName, encoding);
            map.put(fileName, result);
            if (PropKit.prop == null) {
                PropKit.prop = result;
            }
        }
        return result;
    }

    /**
     * 功能：加载配置文件
     * <p>若未加载将加载，若有加载过直接返回</p>
     *
     * @param file 配置文件对象
     * @return
     * @author wsh
     * @date 2021/1/25
     * @see #use(File, String)
     */
    public static Prop use(File file) {
        return use(file, DEFAULT_ENCODING);
    }

    /**
     * 功能：加载配置文件
     * <p>
     * 若未加载将加载，若有加载过直接返回<br>
     * 例如：<br>
     * Prop prop = PropKit.use(new File("/var/config/my_config.txt"), "UTF-8");<br>
     * String userName = prop.get("userName");<br><br>
     * String password = prop.use("my_config.txt").get("password");
     * </p>
     *
     * @param file     配置文件对象
     * @param encoding 配置文件读取编码
     * @return
     * @author wsh
     * @date 2021/1/25
     */
    public static Prop use(File file, String encoding) {
        Prop result = map.get(file.getName());
        if (result == null) {
            result = new Prop(file, encoding);
            map.put(file.getName(), result);
            if (PropKit.prop == null) {
                PropKit.prop = result;
            }
        }
        return result;
    }

    public static Prop useless(String fileName) {
        Prop previous = map.remove(fileName);
        if (PropKit.prop == previous)
            PropKit.prop = null;
        return previous;
    }

    public static void clear() {
        prop = null;
        map.clear();
    }

    public static Prop getProp() {
        if (prop == null) {
            throw new IllegalStateException("Load properties file by invoking PropKit.use(String fileName) method first.");
        }
        return prop;
    }

    public static Prop getProp(String fileName) {
        if (!map.containsKey(fileName)) {
            throw new IllegalStateException("Load properties file by invoking PropKit.use(String fileName) method first.");
        }
        return map.get(fileName);
    }

    public static String get(String key) {
        return getProp().get(key);
    }

    public static String get(String key, String defaultValue) {
        return getProp().get(key, defaultValue);
    }

    public static Integer getInt(String key) {
        return getProp().getInt(key);
    }

    public static Integer getInt(String key, Integer defaultValue) {
        return getProp().getInt(key, defaultValue);
    }

    public static Long getLong(String key) {
        return getProp().getLong(key);
    }

    public static Long getLong(String key, Long defaultValue) {
        return getProp().getLong(key, defaultValue);
    }

    public static Boolean getBoolean(String key) {
        return getProp().getBoolean(key);
    }

    public static Boolean getBoolean(String key, Boolean defaultValue) {
        return getProp().getBoolean(key, defaultValue);
    }

    public static boolean containsKey(String key) {
        return getProp().containsKey(key);
    }
}
